#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import json
import math
import time
from functools import wraps

from flask import make_response
from flask.views import MethodView

from init_extends.init_extends import db
from utils.json_encoder import ComplexEncoder
from utils.log_utils import get_logger

logger = get_logger(__name__)


class BaseModelClass:
    INIT_PAGE = 1
    INIT_SIZE = 10
    INIT_MAX_SIZE = 100

    model_name = None  # model 的 class 名，与 __init__ 中的参数相同

    def __init__(self, model_class=None):
        """
        提供两个使用此类的方式
        :param model_class:
        """
        self._model = model_class if model_class else self.model_name

    def query_all(self, page, size):
        """
        查询当前 model 的所有数据
        :param page:
        :param size:
        :return:
        """
        query_result, total, max_page = self.paginate(self._model.query, page, size)
        return query_result.all()

    def paginate(self, query_data, page, size):
        """
        数据分页逻辑
        :param query_data:
        :param page:
        :param size:
        :return:
        """
        total = query_data.count()
        size = min(max(size, self.INIT_SIZE), self.INIT_MAX_SIZE)
        max_page = math.ceil(total / size)
        page = min(max(page, self.INIT_PAGE), max_page)

        offset_index = (page - 1) * size

        return query_data.limit(size).offset(offset_index), total, max_page

    def filter_query_by(self, filter_data: dict):
        print(self._model.query.filter_by(**filter_data), "======")

    def create(self, **kwargs):
        """
        创建数据
        :param kwargs:
        :return:
        """
        try:
            u = self._model(**kwargs)
            db.session.add(u)
            db.session.commit()
            return u
        except Exception as e:
            print("创建数据失败，>>>>>", e)
            db.session.rollback()

    def get_or_create(self, filter_data, create_data=None, filter_field="id") -> (bool, object):
        """
        根据 filter_field 字段判断是否存在数据。若存在，则返回数据，否则创建数据
        :param filter_data: 用于查询的值
        :param create_data: 不存在数据时，用于创建对象的数据
        :param filter_field: 查询的字段，默认为 id
        :return:
        """

        result = self._model.query.filter_by(**{
            f"{filter_field}": filter_data
        }).first()

        if not result and isinstance(create_data, dict):
            return True, self.create(**create_data)

        return False, result


def execute_time(func):
    """
    统计函数执行时间
    :param func:
    :return:
    """

    @wraps(func)
    def inner(*args, **kwargs):
        _s = time.time()
        result = func(*args, **kwargs)
        _e = time.time() - _s
        logger.info(f"******* 【Func: {func.__name__} time: {'%.2f' % _e} s 】*******")
        return result
    return inner


class BaseMethodView(MethodView):
    """
    统一视图类
    """

    def dispatch_request(self, **kwargs):
        return self.response_handler(super().dispatch_request(**kwargs))

    def response_handler(self, view_response):
        """
        处理视图函数返回值格式
        :param view_response:
        :return:
        """
        response_data = {}

        if isinstance(view_response, tuple):
            if len(view_response) > 1 and isinstance(view_response[1], int):
                response_data['code'] = view_response[1]
            view_response = view_response[0]

        if isinstance(view_response, dict):
            if view_response.get("message"): response_data['message'] = view_response.pop('message')
            if view_response.get("code"): response_data['code'] = view_response.pop('message')

            response_data["data"] = view_response

        elif isinstance(view_response, str):
            response_data["data"] = view_response

        response_data['code'] = response_data.get('code') if response_data.get('code') else 200
        response_data['data'] = response_data.get('data') if response_data.get('data') else 'ok'
        response_data['message'] = response_data.get('message') if response_data.get('message') else 'success'
        # 这里固定返回状态码为 200
        return make_response(response_data, 200)
